/*
 * 文件名：FeeBillDetailServiceImpl.java 描述： 修改人：Administrator 修改时间：2016年4月19日 跟踪单号： 修改单号： 修改内容：
 */

package com.zcsy.manage.service.property.impl;

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.zcsy.commons.constants.Constants;
import com.zcsy.commons.constants.OwnerConstants;
import com.zcsy.commons.model.RequestJson;
import com.zcsy.commons.unique.UniqueNumberUtils;
import com.zcsy.commons.util.DateUtils;
import com.zcsy.manage.model.base.CellHouse;
import com.zcsy.manage.model.base.CommonConfig;
import com.zcsy.manage.model.base.OwnerHouse;
import com.zcsy.manage.model.mall.IntegralConfig;
import com.zcsy.manage.model.mall.IntegralRecord;
import com.zcsy.manage.model.pay.alipay.AliPayResult;
import com.zcsy.manage.model.pay.weixin.PayOrderResultResponse;
import com.zcsy.manage.model.property.FeeBill;
import com.zcsy.manage.model.property.FeeBillDetail;
import com.zcsy.manage.model.system.User;
import com.zcsy.manage.persistence.base.CellHouseDao;
import com.zcsy.manage.persistence.base.CommonConfigDao;
import com.zcsy.manage.persistence.base.OwnerHouseDao;
import com.zcsy.manage.persistence.mall.IntegralConfigDao;
import com.zcsy.manage.persistence.mall.IntegralRecordDao;
import com.zcsy.manage.persistence.property.FeeBillDao;
import com.zcsy.manage.persistence.property.FeeBillDetailDao;
import com.zcsy.manage.persistence.system.UserDao;
import com.zcsy.manage.service.property.IFeeBillDetailService;
import com.zcsy.manage.service.wxpay.service.WxPayResult;

/**
 * @Title: FeeBillDetailServiceImpl.java
 * @Package： com.zcsy.manage.service.property.impl
 * @Description: 物业账单明细服务层实现类
 * @author xujl
 * @Copyright: 2016 武汉中财数元信息技术有限公司 All rights reserved.
 * @date 2016年4月19日
 * @version 1.0
 * @see JDK1.7.0_75
 * @since
 */
@Service
public class FeeBillDetailServiceImpl implements IFeeBillDetailService {
	
	private static Logger log = LoggerFactory.getLogger(FeeBillDetailServiceImpl.class);

    @Autowired
    private FeeBillDetailDao dao;
    
    @Autowired
    private FeeBillDao billDao;
    
    @Autowired
    private CellHouseDao houseDao;
    
    @Autowired
    private UserDao userDao;
    
    @Autowired
    private IntegralConfigDao integralConfigDao;

    @Autowired
    private IntegralRecordDao integralRecordDao;
    
    @Autowired
    private CommonConfigDao commonConfigDao;
    
    @Autowired
    private OwnerHouseDao ownerHouseDao;
    
    @Override
    public int insert(FeeBillDetail record) {
        return dao.insert(record);
    }

    @Override
    public int updateByPrimaryKey(FeeBillDetail record) {
//    	FeeBillDetail oldDetail = dao.selectByPrimaryKey(record.getId());
//    	
//    	oldDetail.setBillNo(record.getBillNo());
//    	oldDetail.setBillTitle(record.getBillTitle());
//    	oldDetail.setBillType(record.getBillType());
//    	oldDetail.setOperator(record.getOperator());
//    	oldDetail.setOperatorAccount(record.getOperatorAccount());
//    	oldDetail.setUpdateTime(record.getUpdateTime());
    	
        return dao.updateByPrimaryKey(record);
    }

    @Override
    public int deleteByPrimaryKey(String id) {
        return dao.deleteByPrimaryKey(id);
    }

    @Override
    public FeeBillDetail selectByPrimaryKey(String id) {
        return dao.selectByPrimaryKey(id);
    }
    
    @Override
    public FeeBillDetail selectByBillID(String billId) {
    	return dao.selectByBillID(billId);
    }
    
    @Override
    public List<FeeBillDetail> selectFeeBillDetailByHouseId(List<String> housesID) {
    	return dao.selectFeeBillDetailByHouseId(housesID);
    }

    @Override
    public List<FeeBillDetail> selectByHouseId(String houseId) {
        return dao.selectByHouseId(houseId);
    }

    @Override
    public List<FeeBill> selectByKeyword(FeeBillDetail record) {
        return dao.selectByKeyword(record);
    }

    @Override
    public FeeBillDetail selectLastBill(String houseId) {
        return dao.selectLastBill(houseId);
    }

    @Override
    public FeeBillDetail getHouseWithProperty(String houseId) {
        return dao.getHouseWithProperty(houseId);
    }
    
    @Override
    public void payFeeBill(String billId , Object payResult){
    	FeeBillDetail detail = selectByPrimaryKey(billId);
    	if(detail != null && (detail.getState().intValue() == Constants.AFTER_STATE
    			|| detail.getState().intValue() == Constants.BEFORE_STATE)){
    		updateFeeBillWhenPayed(detail);
    		
    		detail.setState(Constants.NORMAL_STATE);
    		detail.setPayTime(new Date());
    		detail.setUpdateTime(new Date());
            if(payResult instanceof PayOrderResultResponse) {
            	//微信结果
            	PayOrderResultResponse result = (PayOrderResultResponse)payResult;
            	detail.setPayWay(Constants.PAY_WAY_WXPAY);
            	detail.setPaySystem(Constants.PAY_SYSTEM_WEB);
            	detail.setExternalRespCode(result.getResult_code());
                detail.setExternalTradeNo(result.getOut_trade_no());
                //微信支付返回的金额是以分为单位，所以要除以100
                detail.setTotalFee(
                		new BigDecimal(result.getTotal_fee()).divide(new BigDecimal(100)));
            }else if(payResult instanceof AliPayResult){
            	//支付宝结果
            	AliPayResult result = (AliPayResult)payResult;
            	detail.setPayWay(Constants.PAY_WAY_ALIPAY);
            	detail.setPaySystem(result.getPaySystem());
                detail.setExternalRespCode(result.getExternal_resp_code());
                detail.setExternalTradeNo(result.getExternal_trade_no());
                detail.setTotalFee(result.getTotal_fee());
            }else if(payResult instanceof WxPayResult){
            	//微信app支付
            	WxPayResult result = (WxPayResult)payResult;
            	detail.setPayWay(Constants.PAY_WAY_WXPAY);
            	detail.setPaySystem(result.getPaySystem());
                detail.setExternalRespCode(result.getResultCode());
                detail.setExternalTradeNo(result.getOutTradeNo());
                //微信支付返回的金额是以分为单位，所以要除以100
                detail.setTotalFee(
                		new BigDecimal(result.getTotalFee()).divide(new BigDecimal(100)));
            }
            
            updateByPrimaryKey(detail);
            /**************************************
             * 缴存物业费/停车费，获得积分10分/月 *
             ************************************/
//            FeeBill feeBill = billDao.selectByPrimaryKey(detail.getBillId());
//            OwnerHouse ownerHouse = ownerHouseDao.selectByPrimaryKey(feeBill.getHouseId());
            // 获取当前登陆的用户的信息
            User user = userDao.selectByPrimaryKey(detail.getOperator());

            // 根据唯一标识name获取小区配置信息
            CommonConfig commonConfig = commonConfigDao.getByName("mall_integral_config");

            // 根据唯一标识name获取积分配置信息
            IntegralConfig integralConfig = integralConfigDao.selectByName("payFeeBill");

            if (null != user && null != integralConfig) {
                // 可获得的积分*月数
                Integer integralPay = Integer.valueOf(integralConfig.getValue()) * detail.getMonth();

                // 获取当前用户当天的积分变更记录
                List<IntegralRecord> integralRecordList = integralRecordDao
                        .selectRecordByUserAccount(user.getLoginname());

                // 当前用户当天积分变动之和
                Integer soFarIntegralSum = 0;

                // 求当前用户当天积分变动之和
                for (int i = 0; i < integralRecordList.size(); i++) {
                    if(integralRecordList.get(i).getChange() > 0) {
                        soFarIntegralSum += integralRecordList.get(i).getChange();
                    }
                }

                IntegralRecord integralRecord = new IntegralRecord();
                String integraLabel = integralConfig.getLabel();

                if (commonConfig != null && commonConfig.getValue().matches("[0-9]+")) {

                    // 用户当天可加积分之和的上限
                    Integer maxValuePerDay = Integer.valueOf(commonConfig.getValue());
                    
                    // 用户当天可加积分
                    int available = maxValuePerDay - soFarIntegralSum;
                    // 本次所加积分
                    int addIntegral = available < integralPay ? available : integralPay;

                    if (addIntegral > 0) {
                        user.setIntegral(user.getIntegral() + addIntegral);
                        userDao.updateByPrimaryKeySelective(user);

                        // 插入积分变更信息
                        integralRecord.setId(UniqueNumberUtils.get18UniqueNumber());
                        integralRecord.setChange(addIntegral);
                        integralRecord.setRecordTime(new Date());
                        integralRecord.setUserAccount(user.getLoginname());
                        integralRecord.setDescription(integraLabel);

                        integralRecordDao.insert(integralRecord);
                    }
                }
            }
        }

    }
    
    /** 
     * @Title: updateFeeBillWhenPayed 
     * @Description: 更新物业费账单信息，预缴和欠费缴逻辑
     * @param @param detail     
     * @return void     
     * @throws 
     */
    private void updateFeeBillWhenPayed(FeeBillDetail detail){
    	FeeBill fee = billDao.selectByPrimaryKey(detail.getBillId());
    	FeeBillDetail lastFeeBillDetail = selectLastBill(fee.getHouseId());
    	
    	//状态改为缴费成功，起止时间根据实际情况顺延
		refreshBillTime(detail, lastFeeBillDetail, detail.getMonth());
		
    	if(detail.getState().intValue() == Constants.BEFORE_STATE){
    		//欠费账单付费，直接更新状态和时间，不用管其他预缴订单
    		//预缴账单付费，需要根据情况更改欠费账单信息（欠费账单不能删除）
    		   //缴费后时间<当前时间，更新欠费账单的时间
    		   //缴费后时间>=当前时间，更新欠费账单时间并改为预缴账单
    		FeeBillDetail overdue = dao.selectLastOverdueBill(fee.getHouseId());
    		
    		if(overdue != null){
    			log.debug("查询到欠费账单：" + overdue.getId());
    			
    			Calendar ca = Calendar.getInstance();
    			ca.setTime(new Date());
    			ca.set(ca.get(Calendar.YEAR), ca.get(Calendar.MONTH)
    					, ca.get(Calendar.DATE), 0, 0, 0);
    			Date now = ca.getTime();
    			log.debug("当前时间：" + now.toString());
    			if(detail.getEndDate().compareTo(now) < 0){
    				int diffMonth = getDiffMonth(detail.getEndDate(), now);
    				overdue.setMonth(diffMonth);
    				BigDecimal money = overdue.getArea()
    						.multiply(overdue.getUnitPrice())
    						.multiply(new BigDecimal(overdue.getMonth()))
    						.multiply(overdue.getRate());
    				overdue.setMoney(money);
    				refreshBillTime(overdue, detail, diffMonth);
    				
    				updateByPrimaryKey(overdue);
    				
    				StringBuffer buffer = new StringBuffer("欠费账单修改：");
    				buffer.append(diffMonth);
    				buffer.append("个月---》");
    				buffer.append(money.doubleValue());
    				buffer.append("元---》");
    				buffer.append(overdue.getStartDate());
    				buffer.append("至");
    				buffer.append(overdue.getEndDate());
    				log.debug(buffer.toString());
    			}else{
    				refreshBillTime(overdue, detail, overdue.getMonth());
    				overdue.setState(OwnerConstants.STATE_PRE_PAYING);
    				overdue.setPayWay(Constants.PAY_WAY_UNPAY);
    				overdue.setGenerateWay(OwnerConstants.BILL_DETAIL_PRE_PAYING);
    				
    				updateByPrimaryKey(overdue);
    				
    				StringBuffer buffer = new StringBuffer("欠费账单修改：");
    				buffer.append(overdue.getStartDate());
    				buffer.append("至");
    				buffer.append(overdue.getEndDate());
    				log.debug(buffer.toString());
    			}
    		}
    	}
    }

    @Override
    public FeeBillDetail submitFeeOrder(String houseId, Integer months, String billTitle , User user){
    	if(StringUtils.isEmpty(houseId) || months == null){
    		return null;
    	}
    	
    	// 根据房屋id查询最后一条成功的详细记录
    	FeeBillDetail lastFeeBillDetail = selectLastBill(houseId);
    	if(lastFeeBillDetail == null){
    		return null;
    	}
    	
    	CellHouse cellHouse = houseDao.selectByPrimaryKey(houseId);
    	if(cellHouse == null){
    		return null;
    	}
    	FeeBill bill = getBillByHouse(houseId, cellHouse.getCellId());
    	
    	//生成账单详情
    	FeeBillDetail feeBillDetail = new FeeBillDetail();
    	refreshBillTime(feeBillDetail, lastFeeBillDetail, months);
    	
		
		feeBillDetail.setId(UniqueNumberUtils.get18UniqueNumber());
		feeBillDetail.setBillId(bill.getId());
		
		feeBillDetail.setMonth(months);
		feeBillDetail.setArea(cellHouse.getArea());
		feeBillDetail.setUnitPrice(cellHouse.getPerPrice());
		feeBillDetail.setRate(Constants.INIT_RATE);
		
		BigDecimal money = feeBillDetail.getArea()
				.multiply(feeBillDetail.getUnitPrice())
				.multiply(new BigDecimal(feeBillDetail.getMonth()))
				.multiply(feeBillDetail.getRate());
		
		feeBillDetail.setMoney(money);
		feeBillDetail.setState(OwnerConstants.STATE_PRE_PAYING);
		feeBillDetail.setPayWay(Constants.PAY_WAY_UNPAY);
		feeBillDetail.setGenerateWay(OwnerConstants.BILL_DETAIL_PRE_PAYING);
		feeBillDetail.setOperatorType(OwnerConstants.OPERATOR_TYPE_OWNER);
		feeBillDetail.setOperator(user.getId());
		feeBillDetail.setOperatorAccount(user.getLoginname());
		feeBillDetail.setCreateTime(new Date());
		feeBillDetail.setBillType(OwnerConstants.INVOICE_PERSON);
		feeBillDetail.setBillTitle(billTitle);
		insert(feeBillDetail);
    	
    	return feeBillDetail;
    }
    
    /** 
     * @Title: getDiffMonth 
     * @Description: 获取两个日期的月份差
     * 2016-08-10到2016-09-09算一个月，2016-08-10到2016-09-10就算两个月
     * @param @param beginDate
     * @param @param endDate
     * @param @return     
     * @return int     
     * @throws 
     */
    @Override
    public int getDiffMonth(Date beginDate, Date endDate) {
		if(endDate.compareTo(beginDate) <= 0){
			return 0;
		}
		Calendar calbegin = Calendar.getInstance();
		Calendar calend = Calendar.getInstance();
		calbegin.setTime(beginDate);
		calend.setTime(endDate);
		int m_begin = calbegin.get(Calendar.MONTH) + 1; // 获得合同开始日期月份
		int m_end = calend.get(Calendar.MONTH) + 1;
		// 获得结束日期月份
		int checkmonth = m_end - m_begin
				+ (calend.get(Calendar.YEAR) - calbegin.get(Calendar.YEAR))
				* 12;
		// 获得结束日期于开始的相差月份
		
		//日期加1再比
		int beginDay = calbegin.get(Calendar.DATE);
		int endDay = calend.get(Calendar.DATE);
		int checkday = 0;
		if(endDay + 1 > beginDay){
			checkday = 1;
		}
		
		return checkmonth + checkday;
	}
	
    /** 
     * @Title: refreshBillTime 
     * @Description: 更新账单的时间，根据上次账单的截止时间和本次缴费月数
     * @param @param detail 需要设置的账单详情
     * @param @param lastDate 上次账单
     * @param @param month   本次缴费月数
     * @return void     
     * @throws 
     */
    private void refreshBillTime(FeeBillDetail detail , FeeBillDetail lastDate , int month){
    	Date startDate;
		Date endDate;
		// 最后一条缴费成功记录的结束时间加一天作为新的起始时间
		Calendar cal = Calendar.getInstance();
		cal.setTime(lastDate.getEndDate());
		
		//结束时间大于开始时间日期才加1，等于的时候不加（初始化和导入的初始数据）
		if(lastDate.getEndDate().after(lastDate.getStartDate())){
			cal.add(Calendar.DATE, 1);
		}
		
		startDate = cal.getTime();
		
		//进行日期加月份的计算，获得结束时间
		Calendar date = Calendar.getInstance();
		date.setTime(startDate);
		date.add(Calendar.MONTH, month);
		date.add(Calendar.DATE, -1);
		endDate=date.getTime();
		
		detail.setStartDate(startDate);
		detail.setEndDate(endDate);
    }
    
    @Override
    public FeeBill getBillByHouse(String houseId , String cellId){
    	FeeBill record = new FeeBill();
    	record.setHouseId(houseId);
    	FeeBill bill = billDao.selectByHouseId(houseId);
    	if(bill == null){
    		bill = new FeeBill();
    		bill.setId(UniqueNumberUtils.get18UniqueNumber());
    		bill.setCellId(cellId);
    		bill.setHouseId(houseId);
    		bill.setSendTime(new Date());
    		billDao.insert(bill);
    	}
    	
    	return bill;
    }

    /* (non-Javadoc)
     * @see com.zcsy.manage.service.property.IFeeBillDetailService#selectByHouseIdAndState(java.lang.String)
     */
    @Override
    public List<FeeBillDetail> selectByHouseIdAndState(String houseId) {
        return dao.selectByHouseIdAndState(houseId);
    }
    
    /**
     * @description 后台缴费功能
     * @param houseId 房屋id
     * @param month 月份
     * @param user 用户
     * @param billId 账单id
     * void
     * @author chenxin
     * @date 2016年9月8日下午4:07:33
     */
    @Override
    public void backGroundPay(Date beginD,Date endD,String houseId, Integer month, User user, String billId, Integer billType,
            BigDecimal area,BigDecimal rate, BigDecimal unitPrice, String billTitle, BigDecimal money) {
        // 查询这个房屋是否存在着欠费账单
        FeeBillDetail OverdueBill = dao.selectLastOverdueBill(houseId);
        // 有欠费账单
        if (null != OverdueBill) {
            // 不足额，生成一条后台缴费成功的记录，并修改欠费账单的时间
            if (OverdueBill.getMonth() > month) {
                // 生成一条新的缴费成功记录
                FeeBillDetail newRecord = new FeeBillDetail();

                newRecord.setId(UniqueNumberUtils.get18UniqueNumber());
                newRecord.setBillId(OverdueBill.getBillId());
                newRecord.setStartDate(beginD);
                newRecord.setEndDate(endD);
                newRecord.setMonth(month);
                newRecord.setArea(area);
                newRecord.setRate(rate);
                newRecord.setUnitPrice(unitPrice);
                newRecord.setMoney(money);
                newRecord.setState(Constants.PAY_SUCCESS);// 缴费成功
                newRecord.setPaySystem(Constants.PAY_SYSTEM_WEB);// web
                newRecord.setPayWay(Constants.PAY_WAY_HOUTAI);// 后台缴费
                newRecord.setGenerateWay(Constants.BEFORE_STATE);// 预交费
                newRecord.setOperatorType(Constants.OPERATOR_TYPE_PROPERTY);// 物业
                newRecord.setOperator(user.getLoginname());
                newRecord.setOperatorAccount(user.getId());
                newRecord.setCreateTime(DateUtils.getDate());
                newRecord.setPayTime(DateUtils.getDate());

                dao.insert(newRecord);

                // 修改欠费账单时间
//                int oweMonth = getDiffMonth(endD, OverdueBill.getEndDate());
                int oweMonth = OverdueBill.getMonth() - month;
                OverdueBill.setStartDate(endD);
                OverdueBill.setUpdateTime(DateUtils.getDate());
                OverdueBill.setMonth(oweMonth);
                OverdueBill.setMoney(OverdueBill.getMoney().subtract(money));

                dao.updateByPrimaryKey(OverdueBill);
            } else {// 足额，修改欠费记录时间、状态、缴费方式
                
                OverdueBill.setStartDate(beginD);
                OverdueBill.setEndDate(endD);
                OverdueBill.setState(Constants.PAY_SUCCESS);// 缴费成功
                OverdueBill.setMonth(month);
                OverdueBill.setMoney(money);
                OverdueBill.setRate(rate);
                OverdueBill.setPayWay(Constants.PAY_WAY_HOUTAI);
                OverdueBill.setOperator(user.getLoginname());
                OverdueBill.setOperatorAccount(user.getId());
                OverdueBill.setOperatorType(Constants.OPERATOR_TYPE_PROPERTY);
                OverdueBill.setPayTime(DateUtils.getDate());
                OverdueBill.setUpdateTime(DateUtils.getDate());
                
                dao.updateByPrimaryKey(OverdueBill);
            }
        } else {// 无欠费账单，生成后台缴费成功记录
            // 获得最新一次的缴费记录结束时间，作为这次缴费的起点
            FeeBillDetail feeBillDetail = dao.selectLastBill(houseId);
            Date startDate = feeBillDetail.getEndDate();

            /* 计算提前多缴费的结束日期，获得上一次的缴费结束日期，然后往后推N个月 */
            Calendar c = Calendar.getInstance();// 获得一个日历的实例
            c.setTime(feeBillDetail.getEndDate());// 设置日历时间
            c.add(Calendar.DAY_OF_MONTH, -1); // 设置为前一天
            c.add(Calendar.MONTH, month);// 在日历的月份上增加1个月
            Date endDate = c.getTime();// 的到你想要的日期

            // 生成新的缴费记录
            FeeBillDetail record = new FeeBillDetail();
            record.setId(UniqueNumberUtils.get18UniqueNumber());
            record.setBillId(billId);
            record.setStartDate(startDate);
            record.setEndDate(endDate);
            record.setMonth(month);
            record.setArea(area);
            record.setRate(rate);
            record.setUnitPrice(unitPrice);
            record.setMoney(money);
            record.setState(Constants.PAY_SUCCESS);
            record.setPaySystem(Constants.PAY_SYSTEM_WEB);
            record.setPayWay(Constants.PAY_WAY_HOUTAI);
            record.setGenerateWay(Constants.PRE_PAY);
            record.setOperatorType(Constants.OPERATOR_TYPE_PROPERTY);
            record.setOperator(user.getLoginname());
            record.setOperatorAccount(user.getId());
            record.setCreateTime(DateUtils.getDate());
            record.setPayTime(DateUtils.getDate());
            
            dao.insert(record);
        }
    }
}
